//Author lvzz zhaozhi.lv@163.com

package main

import (
	"bytes"
	"flag"
	"fmt"
	"goframe/cfg"
	"goframe/log"
	"goframe/run"
	"goframe/utils"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const (
	START   string = "start"
	STOP    string = "stop"
	RESTART string = "restart"
	STATUS  string = "status"
)

type runFunc func()
type GoFrame struct {
	PID string
	RUN runFunc
}

func (a *GoFrame) ConvPidAtoi(pid string) int {
	pidInt, err := strconv.Atoi(pid)
	if err != nil {
		return -1
	}
	return pidInt
}

func (a *GoFrame) GetRunEnv() (*GoFrame, error) {
	a.PID = strconv.Itoa(cfg.GetOsPid())
	a.RUN = run.Run
	return a, nil
}

func GetPidFromeFile() int {
	b, _ := ioutil.ReadFile(cfg.PidPath)
	b = bytes.TrimSpace(b)
	pid, _ := strconv.Atoi(string(b))
	return pid
}

func (a *GoFrame) Start() error {
	time.Sleep(time.Duration(1 * time.Second))
	log.Set_log_level(log.LevelDebug)
	if utils.Exists(cfg.PidPath) {
		pid := GetPidFromeFile()
		if err := syscall.Kill(pid, 0); nil == err {
			fmt.Fprintf(os.Stderr, "The program is running, turn off the start again.\n")
			log.Log_Fatal(os.Stderr, "The program is running, turn off the start again.\n")
			return nil
		}
	}
	cfg.WritePidFile(cfg.PidPath, a.PID)
	a.RUN()
	return nil
}

func (a *GoFrame) Stop() error {
	time.Sleep(time.Duration(1 * time.Second))
	if utils.Exists(cfg.PidPath) {
		pid := GetPidFromeFile()
		p, err := os.FindProcess(pid)
		if nil != err {
			return err
		}
		err = p.Kill()
		if nil != err {
			return err
		}
	} else {
		return fmt.Errorf("Unable to read the PID file.")
	}
	return nil
}

func (a *GoFrame) Status() (bool, error) {
	if utils.Exists(cfg.PidPath) {
		pid := GetPidFromeFile()
		if err := syscall.Kill(pid, 0); nil != err {
			return false, nil
		} else {
			return true, nil
		}

	} else {
		return false, fmt.Errorf("Unable to read the PID file.")
	}
}

func main() {
	flag.Parse()
	var cmd string = flag.Arg(0)
	cmd = strings.ToLower(cmd)
	a := &GoFrame{}
	a.GetRunEnv()
	switch strings.TrimSpace(cmd) {
	case START:
		err := a.Start()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STOP:
		err := a.Stop()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
	case STATUS:
		t, err := a.Status()
		if nil != err {
			fmt.Fprintf(os.Stderr, err.Error()+"\n")
		}
		if !t {
			fmt.Fprintf(os.Stdout, "Stop.\n")
		} else {
			fmt.Fprintf(os.Stdout, "Running...\n")
		}
	default:
		fmt.Fprintf(os.Stderr, "Usage: %s command <start|stop|status>\n", os.Args[0])
	}
}
